/******************************************************************************/
/* PODSTAWY GRAFIKI KOMPUTEROWEJ - Laboratorium Komputerowe nr 6              */
/* Grafika rastrowa                                          J. Tarasiuk 2008 */
/******************************************************************************/

#include <wx/scrolwin.h>
#include <wx/dcbuffer.h>
#include "Main_Frm.h"

template <typename T, size_t N>
size_t mygetSize(T(&)[N]) {
    return N;
}

#define MAKE255(x) ((x) > 255 ? 255 : ( (x) < 0 ? 0 : (x) ));

//Do not add custom headers between
//Header Include Start and Header Include End
//wxDev-C++ designer will remove them
////Header Include Start
////Header Include End

//----------------------------------------------------------------------------
// Main_Frm
//----------------------------------------------------------------------------
//Add Custom Events only in the appropriate block.
//Code added in other places will be removed by wxDev-C++
////Event Table Start
BEGIN_EVENT_TABLE(Main_Frm,wxFrame)
	////Manual Code Start
	////Manual Code End

	EVT_CLOSE(Main_Frm::OnClose)
	EVT_BUTTON(ID_WXBUTTON10,Main_Frm::WxButton10Click)
	EVT_BUTTON(ID_WXBUTTON9,Main_Frm::WxButton9Click)

	EVT_COMMAND_SCROLL(ID_WXSCROLLBAR2,Main_Frm::WxScrollBar2Scroll)

	EVT_COMMAND_SCROLL(ID_WXSCROLLBAR1,Main_Frm::WxScrollBar1Scroll)
	EVT_BUTTON(ID_WXBUTTON8,Main_Frm::WxButton8Click)
	EVT_BUTTON(ID_WXBUTTON7,Main_Frm::WxButton7Click)
	EVT_BUTTON(ID_WXBUTTON6,Main_Frm::WxButton6Click)
	EVT_BUTTON(ID_WXBUTTON5,Main_Frm::WxButton5Click)
	EVT_BUTTON(ID_WXBUTTON4,Main_Frm::WxButton4Click)
	EVT_BUTTON(ID_WXBUTTON3,Main_Frm::WxButton3Click)
	EVT_BUTTON(ID_WXBUTTON2,Main_Frm::WxButton2Click)
	EVT_BUTTON(ID_WXBUTTON1,Main_Frm::WxButton1Click)

	EVT_UPDATE_UI(ID_WXSCROLLEDWINDOW1,Main_Frm::WxScrolledWindow1UpdateUI)
END_EVENT_TABLE()
////Event Table End

wxString Float2String(float f, int numdigits)
{
    wxString Result;
    if (numdigits == 0)
    {
      Result = Result.Format(wxT("%f"),f);
    }
    else
    {
        wxString strNumFormat = wxString::Format(wxT("%%0.%df"),numdigits);
        Result = Result.Format(strNumFormat,f);
    }
    return Result;
}

Main_Frm::Main_Frm(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)
: wxFrame(parent, id, title, position, size, style)
{
	CreateGUIControls();
	this->SetBackgroundColour(wxColour(192,192,192));
	wxImage::AddHandler( new wxJPEGHandler );       // Dodajemy handlery do formatow
	wxImage::AddHandler( new wxPNGHandler );        // z jakich bedziemy korzytsac
	wxImage image(wxT("test.jpg"));                      // Tworzymy image wczytujac od razu obrazk z pliku
    if (!image.Ok()) wxMessageBox(wxT("Nie udalo sie zaladowac obrazka"));
    Img_Org=image.Copy();                           // Kopiujemy obrazek do Img_Org
    Img_Cpy=Img_Org.Copy();                         // Kopiujemy obrazek do Img_Cpy
	image.LoadFile(wxT("mask.png"));                     // Wczytujemy obrazek bedacy maska
    if (!image.Ok()) wxMessageBox(wxT("Nie udalo sie zaladowac maski"));
    Img_Mask=image.Copy();                          // Kopiujemy maske do Img_Mask
    WxScrolledWindow1->SetScrollbars(25,25,52,40);  // Ustalamy zakres zmiennosci suwakow okna z suwakami
   	WxScrolledWindow1->SetBackgroundColour(wxColour(192,192,192));
}

Main_Frm::~Main_Frm()
{
}

void Main_Frm::CreateGUIControls()
{
	//Do not add custom code between
	//GUI Items Creation Start and GUI Items Creation End
	//wxDev-C++ designer will remove them.
	//Add the custom code before or after the blocks
	////GUI Items Creation Start

	WxBoxSizer1 = new wxBoxSizer(wxHORIZONTAL);
	this->SetSizer(WxBoxSizer1);
	this->SetAutoLayout(true);

	WxScrolledWindow1 = new wxScrolledWindow(this, ID_WXSCROLLEDWINDOW1, wxPoint(5,5), wxSize(640,480), wxVSCROLL | wxHSCROLL);
	WxScrolledWindow1->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer1->Add(WxScrolledWindow1,1,wxEXPAND | wxALL,5);

	WxGridSizer1 = new wxGridSizer(0, 1, 0, 0);
	WxBoxSizer1->Add(WxGridSizer1, 0, wxALIGN_CENTER | wxALL, 5);

	WxGridSizer2 = new wxGridSizer(0, 2, 0, 0);
	WxGridSizer1->Add(WxGridSizer2, 0, wxALIGN_CENTER | wxALL, 5);

	WxButton1 = new wxButton(this, ID_WXBUTTON1, wxT("Grayscale"), wxPoint(5,5), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton1"));
	WxButton1->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton1,0,wxALIGN_CENTER | wxALL,5);

	WxButton2 = new wxButton(this, ID_WXBUTTON2, wxT("Blur"), wxPoint(90,5), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton2"));
	WxButton2->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton2,0,wxALIGN_CENTER | wxALL,5);

	WxButton3 = new wxButton(this, ID_WXBUTTON3, wxT("Mirror"), wxPoint(5,40), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton3"));
	WxButton3->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton3,0,wxALIGN_CENTER | wxALL,5);

	WxButton4 = new wxButton(this, ID_WXBUTTON4, wxT("Replace"), wxPoint(90,40), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton4"));
	WxButton4->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton4,0,wxALIGN_CENTER | wxALL,5);

	WxButton5 = new wxButton(this, ID_WXBUTTON5, wxT("Rescale"), wxPoint(5,75), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton5"));
	WxButton5->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton5,0,wxALIGN_CENTER | wxALL,5);

	WxButton6 = new wxButton(this, ID_WXBUTTON6, wxT("Rotate"), wxPoint(90,75), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton6"));
	WxButton6->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton6,0,wxALIGN_CENTER | wxALL,5);

	WxButton7 = new wxButton(this, ID_WXBUTTON7, wxT("RotateHue"), wxPoint(5,110), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton7"));
	WxButton7->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton7,0,wxALIGN_CENTER | wxALL,5);

	WxButton8 = new wxButton(this, ID_WXBUTTON8, wxT("Mask"), wxPoint(90,110), wxSize(75,25), 0, wxDefaultValidator, wxT("WxButton8"));
	WxButton8->SetHelpText(wxT("SetMaskFromImage"));
	WxButton8->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxGridSizer2->Add(WxButton8,0,wxALIGN_CENTER | wxALL,5);

	WxBoxSizer2 = new wxBoxSizer(wxVERTICAL);
	WxGridSizer1->Add(WxBoxSizer2, 0, wxALIGN_CENTER | wxALL, 5);

	WxStaticText1 = new wxStaticText(this, ID_WXSTATICTEXT1, wxT("Jasnosc"), wxPoint(64,5), wxDefaultSize, 0, wxT("WxStaticText1"));
	WxStaticText1->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer2->Add(WxStaticText1,0,wxALIGN_CENTER | wxALL,5);

	WxScrollBar1 = new wxScrollBar(this, ID_WXSCROLLBAR1, wxPoint(5,32), wxSize(160,16), wxSB_HORIZONTAL, wxDefaultValidator, wxT("WxScrollBar1"));
	WxScrollBar1->Enable(false);
	WxScrollBar1->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer2->Add(WxScrollBar1,0,wxALIGN_CENTER | wxALL,5);

	WxStaticText2 = new wxStaticText(this, ID_WXSTATICTEXT2, wxT("Kontrast"), wxPoint(62,58), wxDefaultSize, 0, wxT("WxStaticText2"));
	WxStaticText2->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer2->Add(WxStaticText2,0,wxALIGN_CENTER | wxALL,5);

	WxScrollBar2 = new wxScrollBar(this, ID_WXSCROLLBAR2, wxPoint(5,85), wxSize(160,16), wxSB_HORIZONTAL, wxDefaultValidator, wxT("WxScrollBar2"));
	WxScrollBar2->Enable(false);
	WxScrollBar2->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer2->Add(WxScrollBar2,0,wxALIGN_CENTER | wxALL,5);

	WxBoxSizer3 = new wxBoxSizer(wxVERTICAL);
	WxGridSizer1->Add(WxBoxSizer3, 0, wxALIGN_CENTER | wxALL, 5);

	WxButton9 = new wxButton(this, ID_WXBUTTON9, wxT("Maska Prewitta"), wxPoint(5,5), wxSize(150,25), 0, wxDefaultValidator, wxT("WxButton9"));
	WxButton9->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer3->Add(WxButton9,0,wxALIGN_CENTER | wxALL,5);

	WxButton10 = new wxButton(this, ID_WXBUTTON10, wxT("Prog 128"), wxPoint(5,40), wxSize(150,25), 0, wxDefaultValidator, wxT("WxButton10"));
	WxButton10->SetFont(wxFont(8, wxSWISS, wxNORMAL,wxNORMAL, false, wxT("Tahoma")));
	WxBoxSizer3->Add(WxButton10,0,wxALIGN_CENTER | wxALL,5);

	SetTitle(wxT("Lab_06"));
	SetIcon(wxNullIcon);

	GetSizer()->Layout();
	GetSizer()->Fit(this);
	GetSizer()->SetSizeHints(this);
	Center();

	////GUI Items Creation End
	WxScrollBar1->Enable(true);
	WxScrollBar1->SetScrollbar(100, 1, 200, 10);
	WxScrollBar2->Enable(true);
	WxScrollBar2->SetScrollbar(100, 1, 200, 10);
}

void Main_Frm::OnClose(wxCloseEvent& event)
{
	Destroy();
}

/*
 * WxScrolledWindow1UpdateUI
 */
void Main_Frm::WxScrolledWindow1UpdateUI(wxUpdateUIEvent& event)
{
    wxBitmap bitmap(Img_Cpy);           // Tworzymy tymczasowa bitmape na podstawie Img_Cpy
    wxClientDC cdc(WxScrolledWindow1);   // Pobieramy kontekst okna
    wxBufferedDC dc(&cdc);
    WxScrolledWindow1->SetVirtualSize(Img_Cpy.GetWidth(), Img_Cpy.GetHeight());
    WxScrolledWindow1->DoPrepareDC(dc); // Musimy wywolac w przypadku wxScrolledWindow, zeby suwaki prawidlowo dzialaly
    dc.Clear();
    dc.DrawBitmap(bitmap, 0, 0, true);  // Rysujemy bitmape na kontekscie urzadzenia
}

/*
 * WxButton1Click
 */
void Main_Frm::WxButton1Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org.ConvertToGreyscale();
    Update();
}

/*
 * WxButton2Click
 */
void Main_Frm::WxButton2Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org.Blur(5);
}

/*
 * WxButton3Click
 */
void Main_Frm::WxButton3Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org.Mirror();
}

/*
 * WxButton4Click
 */
void Main_Frm::WxButton4Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org;
    Img_Cpy.Replace(254, 0, 0, 0, 0, 255);
}

/*
 * WxButton5Click
 */
void Main_Frm::WxButton5Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org.Scale(320, 240, wxIMAGE_QUALITY_HIGH);
}

/*
 * WxButton6Click
 */
void Main_Frm::WxButton6Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org.Rotate(30.0/180.0 * 3.1415, wxPoint(Img_Cpy.GetWidth()/2, Img_Cpy.GetHeight()/2));
}

/*
 * WxButton7Click
 */
void Main_Frm::WxButton7Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org;
    Img_Cpy.RotateHue(0.5);
    WxScrolledWindow1->Update();
}

/*
 * WxButton8Click
 */
void Main_Frm::WxButton8Click(wxCommandEvent& event)
{
// TO DO: Ustawienie maski obrazu
// #####
// #####
// #####
// #####
// #####
    Img_Cpy = Img_Org;
    Img_Cpy.SetMaskFromImage(Img_Mask, 0, 0, 0);
}

/*
 * WxScrollBar1Scroll
 */
void Main_Frm::WxScrollBar1Scroll(wxScrollEvent& event)
{
// Tutaj, w reakcji na zmiane polozenia suwaka, wywolywana jest funkcja
// Brightness(...), ktora zmienia jasnosc. W tym miejscu nic nie
// zmieniamy. Do uzupelnienia pozostaje funkcja Brightness(...)
	wxEventType eventType = event.GetEventType();
    //if (eventType==10115)
    Brightness(WxScrollBar1->GetThumbPosition()-100);
}

void Main_Frm::Brightness(int value)
{
// TO DO: Zmiana jasnosci obrazu. value moze przyjmowac wartosci od -100 do 100
// #####
// #####
// #####
// #####
    Img_Cpy = Img_Org.Copy();
    unsigned char *data = Img_Cpy.GetData();
    for(long i=0; i<= 3 * Img_Cpy.GetWidth() * Img_Cpy.GetHeight(); ++i)
    {
        int tmp = data[i] + value;
        if(tmp > 255) tmp = 255;
        else if (tmp < 0) tmp = 0;
        data[i] = tmp;
    }
}

/*
 * WxScrollBar2Scroll
 */
void Main_Frm::WxScrollBar2Scroll(wxScrollEvent& event)
{
// Tutaj, w reakcji na zmiane polozenia suwaka, wywolywana jest funkcja
// Contrast(...), ktora zmienia kontrast. W tym miejscu nic nie
// zmieniamy. Do uzupelnienia pozostaje funkcja Contrast(...)
	wxEventType eventType = event.GetEventType();
    //if (eventType==10115)
    Contrast(WxScrollBar2->GetThumbPosition()-100);
}

void Main_Frm::Contrast(int value)
{
    Img_Cpy = Img_Org.Copy();
    unsigned char *data = Img_Cpy.GetData();
    for(long i=0; i<= 3*Img_Cpy.GetWidth() * Img_Cpy.GetHeight(); i+=3)
    {
        data[i] = MAKE255( (data[i] - 128) * (1.0+value/100.0) + 128);
        data[i+1] = MAKE255( (data[i+1] - 128) * (1.0+value/100.0) + 128);
        data[i+2] = MAKE255( (data[i+2] - 128) * (1.0+value/100.0) + 128);
    }
}

/*
 * WxButton9Click
 */
void Main_Frm::WxButton9Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org;
    int f[3][3] = {{-1, 0, 1},
                   {-1, 0, 1},
                   {-1, 0, 1}};
    for(int i=1; i<Img_Cpy.GetWidth(); ++i)
    {
        for(int j=1; j<Img_Cpy.GetHeight(); ++j)
        {

            int r[3][3] = { {Img_Cpy.GetRed(i-1, j-1), Img_Cpy.GetRed(i, j-1), Img_Cpy.GetRed(i+1, j-1)},
                            {Img_Cpy.GetRed(i-1, j), Img_Cpy.GetRed(i, j), Img_Cpy.GetRed(i+1, j)},
                            {Img_Cpy.GetRed(i-1,    j+1), Img_Cpy.GetRed(i,    j+1), Img_Cpy.GetRed(i+1,    j+1)}
                            };

            int g[3][3] = { {Img_Cpy.GetGreen(i-1, j-1), Img_Cpy.GetGreen(i, j-1), Img_Cpy.GetGreen(i+1, j-1)},
                            {Img_Cpy.GetGreen(i-1, j), Img_Cpy.GetGreen(i, j), Img_Cpy.GetGreen(i+1, j)},
                            {Img_Cpy.GetGreen(i-1,    j+1), Img_Cpy.GetGreen(i,    j+1), Img_Cpy.GetGreen(i+1,    j+1)}
                            };

            int b[3][3] = { {Img_Cpy.GetBlue(i-1, j-1), Img_Cpy.GetBlue(i, j-1), Img_Cpy.GetBlue(i+1, j-1)},
                            {Img_Cpy.GetBlue(i-1, j), Img_Cpy.GetBlue(i, j), Img_Cpy.GetBlue(i+1, j)},
                            {Img_Cpy.GetBlue(i-1,    j+1), Img_Cpy.GetBlue(i,    j+1), Img_Cpy.GetBlue(i+1,    j+1)}
                            };

            int s[3];
            /*s[0] = f[0][0] * r[0][0] + f[0][1] * r[0][1] + f[0][2] * r[0][2]
                 + f[1][0] * r[1][0] + f[1][1] * r[1][1] + f[1][2] * r[1][2]
                 + f[2][0] * r[2][0] + f[2][1] * r[2][1] + f[2][2] * r[2][2];

            s[1] = f[0][0] * g[0][0] + f[0][1] * g[0][1] + f[0][2] * g[0][2]
                 + f[1][0] * g[1][0] + f[1][1] * g[1][1] + f[1][2] * g[1][2]
                 + f[2][0] * g[2][0] + f[2][1] * g[2][1] + f[2][2] * g[2][2];

            s[2] = f[0][0] * b[0][0] + f[0][1] * b[0][1] + f[0][2] * b[0][2]
                 + f[1][0] * b[1][0] + f[1][1] * b[1][1] + f[1][2] * b[1][2]
                 + f[2][0] * b[2][0] + f[2][1] * b[2][1] + f[2][2] * b[2][2];*/
            s[0] = MAKE255(-r[0][0] - r[1][0] - r[2][0] + r[0][2] + r[1][2] + r[2][2]);
            s[1] = MAKE255(-g[0][0] - g[1][0] - g[2][0] + g[0][2] + g[1][2] + g[2][2]);
            s[2] = MAKE255(-b[0][0] - b[1][0] - b[2][0] + b[0][2] + b[1][2] + b[2][2]);

            Img_Cpy.SetRGB(i, j, s[0], s[1], s[2]);
        }
    }
}

/*
 * WxButton10Click
 */
void Main_Frm::WxButton10Click(wxCommandEvent& event)
{
    Img_Cpy = Img_Org.Copy();
    unsigned char *data = Img_Cpy.GetData();
    for(long i=0; i<= 3*Img_Cpy.GetWidth() * Img_Cpy.GetHeight(); i+=3)
    {
        data[i] = data[i] <= 128 ? 0 : 255;
        data[i+1] = data[i+1] <= 128 ? 0 : 255;
        data[i+2] = data[i+2] <= 128 ? 0 : 255;
    }
}
